package org.zhaolei.mq;


import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.zhaolei.model.CouponRecordMessage;
import org.zhaolei.service.CouponRecordService;

import java.io.IOException;
import java.util.concurrent.locks.Lock;

@Slf4j
@Component
@RabbitListener(queues = {"${mqconfig.coupon_release_queue}"})   //监听死信队列
public class CouponMQListener {

    @Autowired
    private CouponRecordService couponRecordService;

    @Autowired
    private RedissonClient redissonClient;


    /**
     * 监听死信队列，释放优惠券记录
     * 注意事项：
     * 1. 重复消费-幂等性
     * 2. 消费失败，重新入队后最大重试次数
     * 3. 如果消费失败不重新入队，可以记录日志，然后插入数据库人工排查
     * @param couponRecordMessage
     * @param message
     * @param channel
     */
    @RabbitHandler
    public void releaseCouponRecord(CouponRecordMessage couponRecordMessage, Message message, Channel channel) throws IOException {
        log.info("监听到消息：releaseCouponRecord消息内容：{}", couponRecordMessage);
        long msgTag = message.getMessageProperties().getDeliveryTag();

        boolean flag = couponRecordService.releaseCouponRecord(couponRecordMessage);
//并发可以考虑加锁，串行不需要考虑加锁
//        Lock lock = redissonClient.getLock("lock:coupon_record_release:"+couponRecordMessage.getTaskId());
//        lock.lock();
        try {
            if (flag) {
                //确认消息消费成功
                channel.basicAck(msgTag, false);
            } else {
                log.error("优惠券释放失败 flag=false,{}", couponRecordMessage);
                channel.basicReject(msgTag, true);
            }
        } catch (IOException e) {
            log.error("释放优惠券记录异常:{},msg:{}", e, couponRecordMessage);
            channel.basicReject(msgTag, true);
        }
//        finally {
//            lock.unlock();
//        }
    }

}
